package com.ljqc.sbom.management;


import com.ljqc.sbom.management.util.RedissonProperties;
import com.ljqc.sbom.management.util.SpringContextUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.SingleServerConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.util.UrlPathHelper;

import java.io.IOException;

@SpringBootApplication
@EnableEurekaClient
@EnableCaching
@EnableAsync
@EnableFeignClients
@EnableJpaRepositories(basePackages = {"com.ljqc.sbom.management.repository"})
public class Application extends WebMvcConfigurerAdapter implements ApplicationListener<ContextRefreshedEvent> {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }


    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        SpringContextUtil.setApplicationContext(event.getApplicationContext());
    }

    @Bean(name = "restSync")
    public RestTemplate restTemplate() {
        //        factory.setConnectionRequestTimeout(3000);
        HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
        httpRequestFactory.setConnectionRequestTimeout(60000);
        httpRequestFactory.setConnectTimeout(60000);
        httpRequestFactory.setReadTimeout(60000);
        //        httpRequestFactory.setBufferRequestBody(false);
        RestTemplate restTemplate = new RestTemplate(httpRequestFactory);
        restTemplate.getInterceptors().add(new ClientHttpRequestConnectionCloseInterceptor());
        return restTemplate;
    }

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        UrlPathHelper urlPathHelper = new UrlPathHelper();
        urlPathHelper.setUrlDecode(false);
        configurer.setUrlPathHelper(urlPathHelper);
    }


    @Slf4j
    static
    class ClientHttpRequestConnectionCloseInterceptor implements ClientHttpRequestInterceptor {

        private static final String NO_CONNECTION_UPDATE = "NoConnectionUpdate";

        private static final String CONNECTION_UP = "Connection";

        private static final String CONNECTION_LOW = "connection";

        @Override
        public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
            try {
                HttpHeaders headers = httpRequest.getHeaders();
                if (headers.containsKey(NO_CONNECTION_UPDATE)) {
                    log.info("skip connection intercept");
                } else {
                    if (!headers.containsKey(CONNECTION_UP) && !headers.containsKey(CONNECTION_LOW)) {
                        headers.set(CONNECTION_LOW, "close");
                    }
                }
            } catch (Exception e) {
                log.error("http request intercept fail, {}", e.getMessage(), e);
            }
            return clientHttpRequestExecution.execute(httpRequest, bytes);
        }
    }


    /**
     * 单机模式自动装配
     *
     * @return
     */
    @Bean
    @ConditionalOnProperty(name = "redisson.address")
    RedissonClient redissonClient(RedissonProperties redissonProperties) {
        Config config = new Config();
        SingleServerConfig serverConfig = config.useSingleServer()
                .setAddress(redissonProperties.getAddress())
                .setTimeout(redissonProperties.getTimeout())
                .setConnectionPoolSize(redissonProperties.getConnectionPoolSize())
                .setConnectionMinimumIdleSize(redissonProperties.getConnectionMinimumIdleSize())
                .setPingConnectionInterval(redissonProperties.getPingConnectionInterval())
                .setDnsMonitoringInterval(redissonProperties.getDnsMonitoringInterval());

        if (StringUtils.isNotBlank(redissonProperties.getPassword())) {
            serverConfig.setPassword(redissonProperties.getPassword());
        }

        return Redisson.create(config);
    }


}
